import java.util.*;

public class InfiniteLab {
	private int[] dRow = {0, 1, 0, -1};
	private int[] dColumn = {1, 0, -1, 0};

	public long getDistance(String[] map_, long r1, int c1, long r2, int c2) {
		char[][] map = new char[map_.length][];
		for (int i = 0; i < map.length; i++)
			map[i] = map_[i].toCharArray();
		int height = map.length;
		int width = map[0].length;
		int countFree = 0;
		for (char[] row : map) {
			for (char cell : row) {
				if (cell != '#')
					countFree++;
			}
		}
		int[] sumTeleports = new int[height];
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				if (map[i][j] == 'T')
					sumTeleports[i] += j;
			}
		}
		long[][][][] distance = new long[height][width][2 * height][width];
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				if (map[i][j] == '#')
					continue;
				for (long[] row : distance[i][j])
					Arrays.fill(row, Long.MAX_VALUE / 2);
				int remaining = 2 * countFree - 1;
				Queue<Integer> queue = new LinkedList<Integer>();
				Map<Integer, Integer> dist = new HashMap<Integer, Integer>();
				queue.add(i * width + j);
				dist.put(i * width + j, 0);
				while (!queue.isEmpty() && remaining != 0) {
					int key = queue.poll();
					int row = divide(key, width);
					int column = remainder(key, width);
					int curDistance = dist.get(key);
					for (int k = 0; k < 4; k++) {
						int nextRow = row + dRow[k];
						int nextColumn = column + dColumn[k];
						int mapRow = remainder(nextRow, height);
						if (nextColumn >= 0 && nextColumn < width && map[mapRow][nextColumn] != '#')
							remaining -= tryAdd(nextRow, nextColumn, queue, dist, distance[i][j], width, curDistance);
					}
					int mapRow = remainder(row, height);
					if (map[mapRow][column] == 'T')
						remaining -= tryAdd(row, sumTeleports[mapRow] - column, queue, dist, distance[i][j], width, curDistance);
				}
			}
		}
		if (r1 > r2) {
			long t = r1;
			r1 = r2;
			r2 = t;
			int temp = c1;
			c1 = c2;
			c2 = temp;
		}
		long shift = remainder(r1, height);
		r1 -= shift * height;
		r2 -= shift * height;
		if (r2 < 2 * height)
			return adjustValue(distance[((int) r1)][c1][((int) r2)][c2]);
		long[][] matrix = new long[width * height][width * height];
		for (int i = 0; i < height; i++) {
			for (int j = 0; j < width; j++) {
				for (int k = 0; k < height; k++) {
					for (int l = 0; l < width; l++)
						matrix[i * width + j][k * width + l] = distance[i][j][k + height][width];
				}
			}
		}
		long[][] resultMatrix = new long[width * height][width * height];
		for (int i = 0; i < resultMatrix.length; i++)
			resultMatrix[i][i] = 1;
		long[][] helpMatrix = new long[width * height][width * height];
		for (int i = 0; i < resultMatrix.length; i++)
			helpMatrix[i][i] = 1;
		power(resultMatrix, matrix, helpMatrix, r2 / height);
		return adjustValue(resultMatrix[((int) r1) * width + c1][((int) ((r2 % height) * width + c2))]);
	}

	private void power(long[][] resultMatrix, long[][] matrix, long[][] helpMatrix, long n) {
		if (n == 0)
			return;
		if (n % 2 == 1) {
			power(resultMatrix, matrix, helpMatrix, n / 2);
			multiply(helpMatrix, resultMatrix, resultMatrix);
			multiply(resultMatrix, helpMatrix, matrix);
		} else {
			power(helpMatrix, matrix, resultMatrix, n / 2);
			multiply(resultMatrix, helpMatrix, helpMatrix);
		}
	}

	private void multiply(long[][] a, long[][] b, long[][] c) {
		for (int i = 0; i < a.length; i++) {
			for (int j = 0; j < a.length; j++)
				a[i][j] = Long.MAX_VALUE / 2;
		}
		for (int i = 0; i < a.length; i++) {
			for (int j = 0; j < a.length; j++) {
				for (int k = 0; k < a.length; k++) {
					a[i][k] = Math.min(a[i][k], b[i][j] + c[j][k]);
				}
			}
		}
	}

	private long adjustValue(long value) {
		if (value == Long.MAX_VALUE / 2)
			return -1;
		return value;
	}

	private int tryAdd(int row, int column, Queue<Integer> queue, Map<Integer, Integer> dist, long[][] distance,
			int width, int curDistance)
	{
		int key = row * width + column;
		if (dist.containsKey(key))
			return 0;
		dist.put(key, curDistance + 1);
		queue.add(key);
		if (row >= 0 && row < distance.length) {
			distance[row][column] = curDistance + 1;
			return 1;
		}
		return 0;
	}

	private int remainder(int key, int width) {
		key %= width;
		if (key < 0)
			key += width;
		return key;
	}

	private long remainder(long key, int width) {
		key %= width;
		if (key < 0)
			key += width;
		return key;
	}

	private int divide(int key, int width) {
		if (remainder(key, width) == 0)
			return key / width;
		return key >= 0 ? key / width : key / width - 1;
	}

	// BEGIN CUT HERE
   public static void main(String[] args) {
		if ( args.length == 0 ) {
			InfiniteLabHarness.run_test(-1);
		} else {
			for ( int i=0; i<args.length; ++i )
				InfiniteLabHarness.run_test(Integer.valueOf(args[i]));
		}
	}
// END CUT HERE
}

// BEGIN CUT HERE
class InfiniteLabHarness {
	public static void run_test( int casenum ) {
		if ( casenum != -1 ) {
			if ( runTestCase( casenum ) == -1 )
				System.err.println("Illegal input! Test case " + casenum + " does not exist.");
			return;
		}
		
		int correct = 0, total = 0;
		for ( int i=0;; ++i ) {
			int x = runTestCase(i);
			if ( x == -1 ) {
				if ( i >= 100 ) break;
				continue;
			}
			correct += x;
			++total;
		}
		
		if ( total == 0 ) {
			System.err.println("No test cases run.");
		} else if ( correct < total ) {
			System.err.println("Some cases FAILED (passed " + correct + " of " + total + ").");
		} else {
			System.err.println("All " + total + " tests passed!");
		}
	}
	
	static boolean compareOutput(long expected, long result) { return expected == result; }
	static String formatResult(long res) {
		return String.format("%d", res);
	}
	
	static int verifyCase( int casenum, long expected, long received ) { 
		System.err.print("Example " + casenum + "... ");
		if ( compareOutput( expected, received ) ) {
			System.err.println("PASSED");
			return 1;
		} else {
			System.err.println("FAILED");
			System.err.println("    Expected: " + formatResult(expected)); 
			System.err.println("    Received: " + formatResult(received)); 
			return 0;
		}
	}

	static int runTestCase( int casenum ) {
		switch( casenum ) {
		case 0: {
			String[] map              = {"#...##",  ".##...",  "..#.##",  "#.#.##"};
			long r1                   = 1L;
			int c1                    = 0;
			long r2                   = 5L;
			int c2                    = 3;
			long expected__           = 7L;

			return verifyCase( casenum, expected__, new InfiniteLab().getDistance( map, r1, c1, r2, c2 ) );
		}
		case 1: {
			String[] map              = {"##.#.",  ".#T#T",  "...#.",  "##.#."};
			long r1                   = 7L;
			int c1                    = 4;
			long r2                   = 1L;
			int c2                    = 0;
			long expected__           = 9L;

			return verifyCase( casenum, expected__, new InfiniteLab().getDistance( map, r1, c1, r2, c2 ) );
		}
		case 2: {
			String[] map              = {"..######.#",  ".###T###.T",  "..T#.##T##",  ".######..#"};
			long r1                   = 1L;
			int c1                    = 0;
			long r2                   = 6L;
			int c2                    = 4;
			long expected__           = 11L;

			return verifyCase( casenum, expected__, new InfiniteLab().getDistance( map, r1, c1, r2, c2 ) );
		}
		case 3: {
			String[] map              = {"..#..",  ".#.#.",  "....."};
			long r1                   = -29L;
			int c1                    = 2;
			long r2                   = 19L;
			int c2                    = 2;
			long expected__           = 54L;

			return verifyCase( casenum, expected__, new InfiniteLab().getDistance( map, r1, c1, r2, c2 ) );
		}
		case 4: {
			String[] map              = {".#.#.",  "..#..",  ".....",  ".....",  "..#.."};
			long r1                   = -999L;
			int c1                    = 3;
			long r2                   = 100L;
			int c2                    = 2;
			long expected__           = -1L;

			return verifyCase( casenum, expected__, new InfiniteLab().getDistance( map, r1, c1, r2, c2 ) );
		}

		// custom cases

/*      case 5: {
			String[] map              = ;
			long r1                   = L;
			int c1                    = ;
			long r2                   = L;
			int c2                    = ;
			long expected__           = L;

			return verifyCase( casenum, expected__, new InfiniteLab().getDistance( map, r1, c1, r2, c2 ) );
		}*/
/*      case 6: {
			String[] map              = ;
			long r1                   = L;
			int c1                    = ;
			long r2                   = L;
			int c2                    = ;
			long expected__           = L;

			return verifyCase( casenum, expected__, new InfiniteLab().getDistance( map, r1, c1, r2, c2 ) );
		}*/
/*      case 7: {
			String[] map              = ;
			long r1                   = L;
			int c1                    = ;
			long r2                   = L;
			int c2                    = ;
			long expected__           = L;

			return verifyCase( casenum, expected__, new InfiniteLab().getDistance( map, r1, c1, r2, c2 ) );
		}*/
		default:
			return -1;
		}
	}
}

// END CUT HERE
